package com.itita.ww2.game.user;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.Seconds;

import com.itita.ww2.core.MessageHandler;
import com.itita.ww2.data.GuideConfig;
import com.itita.ww2.data.MissionConfig;
import com.itita.ww2.data.PlayerConfig;
import com.itita.ww2.enums.PushCode;
import com.itita.ww2.game.user.UserRewardDispatch.IUserRewardListener;
import com.itita.ww2.game.user.UserRewardDispatch.RewardType;
import com.itita.ww2.model.enums.ResourceType;
import com.itita.ww2.model.user.DevTime;
import com.itita.ww2.model.user.DevTime.DevTimeType;
import com.itita.ww2.model.user.UserFatigue;
import com.itita.ww2.model.user.UserProfile;
import com.itita.ww2.redis.RedisUtil;
import com.itita.ww2.redis.cache.Table;
import com.itita.ww2.utils.DataUtil;
import com.itita.ww2.utils.TimeUtil;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;

/**
 * 玩家的其他信息
 * @author NorthLan
 *
 */
public class UserInfo {
	// private static final Logger logger = LoggerFactory.getLogger(UserInfo.class);
	private int uid;
	private UserProfile userProfile;
	// 
	private UserFatigue fatigue;
	// 
	private int level; // 等级
	private int exp; // 经验
	// 
	private int guideStep; // 新手引导当前已完成的步骤
	private int vipLv; // vip等级
	//
	private boolean isFirstJoinAl = true; // 是否首次加入联盟

	//	private long lastUpdateTime; // 上次更新时间 
	private Vector<IUserLevelListener> userLevelListeners;

	public UserInfo(UserProfile userProfile) {
		this.userProfile = userProfile;
		this.uid = userProfile.getUid();
		userLevelListeners = new Vector<>();
	}

	public void addListener(IUserLevelListener listener) {
		this.userLevelListeners.addElement(listener);
	}

	/*
	 * ******************** Opers
	 */

	public void setGuideStep(int step) {
		// logger.info("step: {} TO {}", guideStep, step);
		if (this.guideStep >= step) {
			return;
		}
		this.guideStep = step;

		// 
		ISFSObject resObj = GuideConfig.getGuildRewardByStep(step);
		userProfile.getResManager().operResWithMaxCheck(resObj, true);
		userProfile.getResManager().update();
		userProfile.getResManager().sync();
		// 
		update();
	}

	public final boolean isFirstJoinAl() {
		return isFirstJoinAl;
	}

	public final void setFirstJoinAl(boolean isFirstJoinAl) {
		this.isFirstJoinAl = isFirstJoinAl;
	}

	/**
	 * 补满疲劳值
	 */
	public boolean fillFatigue() {
		int max = PlayerConfig.getMaxFatiguePoints(this.level);
		int count = max - getFatigue(); // 需要补充点数
		if (count == 0) {
			return false;
		}

		// 次数限制
		int limit = PlayerConfig.getFatigueBuyLimit(this.vipLv);
		if (this.fatigue.getFfCount() >= limit) {
			return false;
		}

		// 金条足够否(资源条件)
		int needGold = caculateFatigueGold(count, this.fatigue.getFfCount());
		if (!userProfile.getResManager().isResEnoughSingle(ResourceType.GOLD, needGold)) {
			return false;
		}
		// 消耗
		userProfile.getResManager().operRes(ResourceType.GOLD, -needGold);
		userProfile.getResManager().update();
		userProfile.getResManager().sync();
		// 填满
		this.fatigue.setFatigue(max);
		this.fatigue.setLastFFTime(TimeUtil.getUtcNowMillis());
		this.fatigue.addFfCount();
		// 
		update();
		syncFatigue();

		return true;
	}

	public void resetFfCount() {
		this.fatigue.resetFfCount();
	}

	/**
	 * 计算疲劳对应金条数
	 */
	private int caculateFatigueGold(int count, int times) {
		return PlayerConfig.getGoldPerFatigue(times) * count;
	}

	/**
	 * 消耗体力
	 */
	public boolean fatigueCostByMission(String missionId) {
		if (!isFatigueEnough(missionId)) {
			return false;
		}
		fatigueOper(-MissionConfig.getCostFatigue(missionId));
		update();
		syncFatigue();
		return true;
	}

	public boolean isFatigueEnough(String missionId) {
		return this.fatigue.getFatigue() >= MissionConfig.getCostFatigue(missionId);
	}

	/**
	 * 增长用户经验值
	 */
	public int growExpByMission(String missionId) {
		int exp = MissionConfig.getRewardCommanderExp(missionId);
		expGrow(exp);
		update();
		syncExp();
		return exp;
	}

	/**
	 * 经验增长,支持一次升多级
	 */
	public boolean expGrow(int value) {
		if (this.level >= PlayerConfig.getMaxLevel()) {
			return false;
		}
		this.exp += value;
		int needExp = 0;
		do {
			// 获取当前等级升级需要的经验
			needExp = PlayerConfig.getNeedExp(this.level);
			if (this.exp >= needExp) {
				// 升级,经验归零,但要保留溢出
				this.exp -= needExp;
				this.level++;
				// 触发监听器,消费者自行处理逻辑
				Iterator<IUserLevelListener> iter = userLevelListeners.iterator();
				while (iter.hasNext()) {
					iter.next().onUserLevelUp(this.level);
				}
			}
		} while (this.exp >= needExp);
		//		if (ret) {
		//			DBManager.getInstance().updateAggrUserLevel(this.uid, this.level);
		//		}
		return true;
	}

	public void fatigueOper(int value) {
		this.fatigue.setFatigue(Math.max(0, getFatigue() + value));
	}

	/**
	 * 疲劳回复
	 * 返回下一次恢复时间
	 */
	public synchronized int fatigueRestore() {
		int duration = PlayerConfig.getFatigueDuration();
		UserDevTimeManager manager = userProfile.getTimeManager();
		DevTime devTime = null;
		if (!manager.isDevTimeExists(DevTimeType.FATIGUE, "")) {
			manager.addFatigueDevTime();
			manager.update();
		}
		devTime = manager.getDevTime(DevTimeType.FATIGUE, "");

		DateTime lastTime = new DateTime(devTime.getEndTime(), DateTimeZone.UTC);
		DateTime nowTime = TimeUtil.getUtcNow();
		int deltaSec = Seconds.secondsBetween(lastTime, nowTime).getSeconds(); // 上次与现在时间间隔
		int count = deltaSec / duration; // 恢复的次数
		if (count <= 0) {
			return duration - deltaSec;
		} else {
			// 回复疲劳,如果要恢复的疲劳大于最大值,不做操作
			int restorePoint = count;
			boolean succ = false;
			int maxFatigue = PlayerConfig.getMaxFatiguePoints(this.level);
			if (getFatigue() < maxFatigue) {
				// 回复,但注意限定
				if (getFatigue() + count >= maxFatigue) {
					restorePoint = maxFatigue - getFatigue();
				}
				succ = true;
			}
			if (succ) {
				fatigueOper(restorePoint);
				update();
			}
			// 时间更新
			devTime.updateEndTime(nowTime.getMillis());
			manager.update();
			return duration;
		}
	}

	//	/**
	//	 * 获取用户最大派兵数量
	//	 */
	//	public int getDispatchMaximum() {
	//		return PlayerConfig.getDispatchCount(this.level);
	//	}

	/**
	 * 获取玩家当前最大库存量
	 */
	public int getMaxArmyStock() {
		return PlayerConfig.getArmyStockCount(this.level);
	}

	public int getLevel() {
		return this.level;
	}

	public int getFatigue() {
		return this.fatigue.getFatigue();
	}

	/*
	 * *********************** Sync.
	 */

	/**
	 * 同步疲劳
	 */
	public synchronized void syncFatigue() {
		ISFSObject pushObj = SFSObject.newInstance();
		pushObj.putInt("fatigue", getFatigue());
		pushObj.putInt("count", this.fatigue.getFfCount());
		MessageHandler.getInstance().pushUser(PushCode.FATIGUE, pushObj, userProfile.getSFSUser());
	}

	/**
	 * 同步经验
	 */
	public synchronized void syncExp() {
		ISFSObject pushObj = SFSObject.newInstance();
		pushObj.putInt("exp", this.exp);
		pushObj.putInt("lv", this.level);
		MessageHandler.getInstance().pushUser(PushCode.LEVEL_EXP, pushObj, userProfile.getSFSUser());
	}

	/**
	 * 同步引导步骤
	 */
	public synchronized void syncGuideStep() {
		ISFSObject pushObj = SFSObject.newInstance();
		pushObj.putInt("guidestep", guideStep);
		MessageHandler.getInstance().pushUser(PushCode.GUIDESTEP, pushObj, userProfile.getSFSUser());
	}

	/**
	 * 加载资源
	 */
	public synchronized void load() {
		Table t = UserService.getInstance().getCacheUserDataTable();
		ISFSObject ret = SFSObject.newFromJsonData(t.getValue(RedisUtil.genericKey(this.uid), "info"));
		this.level = ret.getInt("lv");
		this.exp = ret.getInt("exp");
		// 
		this.fatigue = UserFatigue.newFromJsonData(ret.getSFSObject("fatigue").toJson());
		// 
		this.guideStep = DataUtil.intValueOf(t.getValue(RedisUtil.genericKey(this.uid), "guideStep"));
		this.vipLv = DataUtil.intValueOf(t.getValue(RedisUtil.genericKey(this.uid), "vipLv"));
		int isFirstJoinAlInt = DataUtil.intValueOf(t.getValue(RedisUtil.genericKey(this.uid), "firstJoinAl"));
		this.isFirstJoinAl = isFirstJoinAlInt == 1 ? true : false;
	}

	/**
	 * 更新到redis
	 */
	public synchronized void update() {
		Table t = UserService.getInstance().getCacheUserDataTable();
		t.setValue(RedisUtil.genericKey(this.uid), "info", toSFSObject().toJson());
		t.setValue(RedisUtil.genericKey(this.uid), "guideStep", this.guideStep);
		t.setValue(RedisUtil.genericKey(this.uid), "vipLv", this.vipLv);
		t.setValue(RedisUtil.genericKey(this.uid), "firstJoinAl", this.isFirstJoinAl ? 1 : 0);
		// 更新时间
		// lastUpdateTime = TimeUtil.getUtcNow().getMillis();
	}

	public ISFSObject toSFSObject() {
		ISFSObject ret = SFSObject.newInstance();
		ret.putInt("lv", this.level);
		ret.putInt("exp", this.exp);
		ret.putSFSObject("fatigue", this.fatigue.toSFSObject());
		return ret;
	}

	private boolean isInit() {
		com.itita.ww2.redis.cache.Table t = UserService.getInstance().getCacheUserDataTable();
		String data = t.getValue(RedisUtil.genericKey(userProfile.getUid()), "info");
		return StringUtils.isNotBlank(data) && !data.equals("null");
	}

	/**
	 * 初始化数据
	 */
	public void initialize() {
		if (!isInit()) {
			this.fatigue = new UserFatigue();
			this.fatigue.setFatigue(PlayerConfig.getGameInitFatigue());
			this.level = PlayerConfig.getGameInitLevel();
			this.exp = PlayerConfig.getGameInitExp();
			this.guideStep = 0;
			this.vipLv = 0;
			this.isFirstJoinAl = true;
			this.update();
		} else {
			load();
		}
		userProfile.getRewardManager().addListener(new UserRewardImpl());
	}

	/**
	 * 玩家等级监听
	 * @author NorthLan
	 */
	public static interface IUserLevelListener {
		public void onUserLevelUp(int level); // 玩家升级时
	}

	public int getGuideStep() {
		return this.guideStep;
	}

	public int getVipLv() {
		return vipLv;
	}

	class UserRewardImpl implements IUserRewardListener {

		@Override
		public Map<String, Object> onReward(RewardType type, ISFSObject params) throws Exception {
			Map<String, Object> ret = new HashMap<>();
			switch (type) {
			case MISSION_COMPLETE:
				ret = onMissionComplete(params.getUtfString("missionId"));
				break;
			default:
				break;
			}
			return ret;
		}

		private Map<String, Object> onMissionComplete(String missionId) throws Exception {
			Map<String, Object> ret = new HashMap<>();
			int exp = growExpByMission(missionId);
			ret.put("cmd_exp", exp);
			return ret;
		}
	}
}
